package cn.wolfcode.service.impl;

import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AliPayFeignApi;
import cn.wolfcode.feign.IntegralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * Created by wolfcode-lanxw
 */
@Service
@Transactional
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private AliPayFeignApi aliPayFeignApi;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IntegralFeignApi integralFeignApi;

    // 获取订单
    @Override
    public OrderInfo get(String orderNo) {
        OrderInfo orderInfo = null;
        // 先从redis中查
        String info = (String) redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo + "");
        if (StringUtils.isEmpty(info)) {
            // 如果redis中没有就从数据库中查
            orderInfo = orderInfoMapper.find(orderNo);
            // 并设置到redis中
            redisTemplate.opsForHash().put(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo + "", JSON.toJSONString(orderInfo));
        } else {
            orderInfo = JSON.parseObject(info, OrderInfo.class);
        }
        return orderInfo;
    }

    // 修改订单状态为取消
    @Override
    @Transactional
    public void changeCancelStatus(String orderNo, Integer status) {
        if (!StringUtils.isEmpty(orderNo) && status != null) {
            orderInfoMapper.updateCancelStatus(orderNo, status);
        }
    }

    // 支付宝支付成功
    @Override
    @Transactional
    public void paySuccess(Map<String, String> params) {
        // 插入支付流水
        PayLog payLog = new PayLog();
        String outTradeNo = params.get("out_trade_no");
        payLog.setTradeNo(outTradeNo);
        payLog.setNotifyTime(getNow());
        payLog.setTotalAmount(params.get("total_amount"));
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLogMapper.insert(payLog);
        // 订单状态修改
        orderInfoMapper.changePayStatus(outTradeNo, OrderInfo.STATUS_ACCOUNT_PAID , OrderInfo.PAYTYPE_ONLINE);
    }

    // 积分支付
    @Override
    @GlobalTransactional
    public void payIntegral(OrderInfo orderInfo) {
        OperateIntergralVo vo = new OperateIntergralVo();
        String orderNo = orderInfo.getOrderNo();
        vo.setPk(orderNo);
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        vo.setInfo(orderInfo.getProductName());
        Result<Boolean> result = integralFeignApi.payIntegral(vo);
        if (result != null && !result.hasError()) {
            if (result.getData()) {
                // 插入支付流水
                PayLog payLog = new PayLog();
                payLog.setTradeNo(orderNo);
                payLog.setNotifyTime(getNow());
                payLog.setTotalAmount(orderInfo.getIntergral() + "");
                payLog.setPayType(OrderInfo.PAYTYPE_INTERGRAL);
                payLogMapper.insert(payLog);
                // 订单状态修改
                orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID , OrderInfo.PAYTYPE_INTERGRAL);
            }
        }
    }

    // 积分退款
    @Override
    @GlobalTransactional
    public void refundIntegral(OrderInfo orderInfo) {
        // 插入退款流水
        createRefundLog(orderInfo, OrderInfo.PAYTYPE_INTERGRAL);
        // 调用积分减少
        OperateIntergralVo vo = new OperateIntergralVo();
        String orderNo = orderInfo.getOrderNo();
        vo.setPk(orderNo);
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        vo.setInfo(orderInfo.getProductName());
        Result<Boolean> result = integralFeignApi.refundIntegral(vo);
        if (result != null && !result.hasError()) {
            if (result.getData()) {
                // 订单状态修改
                orderInfoMapper.changeRefundStatus(orderNo, OrderInfo.STATUS_REFUND);
                // 回补真实库存
                Long seckillId = orderInfo.getSeckillId();
                seckillProductService.incrStock(seckillId);
                // 回补预库存
                Integer time = orderInfo.getSeckillTime();
                seckillProductService.rollbackRedisStock(time, seckillId);
                // 修改订单标识
                rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, seckillId);
            }
        }
    }

    // 支付宝退款
    @Override
    @Transactional
    public void refundAliPay(OrderInfo orderInfo) {
        // 插入退款流水
        createRefundLog(orderInfo, OrderInfo.PAYTYPE_ONLINE);
        // 退款
        RefundVo refundVo = new RefundVo();
        String orderNo = orderInfo.getOrderNo();
        refundVo.setOutTradeNo(orderNo);
        refundVo.setRefundAmount(orderInfo.getSeckillPrice() + "");
        refundVo.setRefundReason("garbage , don't want");
        Result<Boolean> refund = aliPayFeignApi.refund(refundVo);
        if (refund != null && !refund.hasError()) {
            if (refund.getData()) {
                // 订单状态修改
                orderInfoMapper.changeRefundStatus(orderNo, OrderInfo.STATUS_REFUND);
                // 回补真实库存
                Long seckillId = orderInfo.getSeckillId();
                seckillProductService.incrStock(seckillId);
                // 回补预库存
                Integer time = orderInfo.getSeckillTime();
                seckillProductService.rollbackRedisStock(time, seckillId);
                // 修改订单标识
                rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, seckillId);
            }
        }
    }

    // 秒杀业务
    @Override
    @Transactional
    public String doSeckill(int time, Long seckillId, Long phone) {
        SeckillProductVo vo = seckillProductService.find(time, seckillId);
        //   创建订单对象并存入mysql中
        OrderInfo info = createOrder(time, seckillId, phone, vo);
        orderInfoMapper.insert(info);
        //   真实库存减少1
        seckillProductService.decrStockCount(seckillId);
        //   往redis中存入订单信息为重复下单判断做准备
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(phone + ""), seckillId + "");
        return info.getOrderNo();
    }

    // 创建订单
    private OrderInfo createOrder(int time, Long seckillId, Long phone, SeckillProductVo vo) {
        OrderInfo info = new OrderInfo();
        info.setOrderNo(IdGenerateUtil.get().nextId() + "");
        info.setUserId(phone);
        info.setProductId(vo.getProductId());
        info.setDeliveryAddrId(1L);
        info.setProductName(vo.getProductName());
        info.setProductImg(vo.getProductImg());
        info.setProductCount(vo.getStockCount());
        info.setProductPrice(vo.getProductPrice());
        info.setSeckillPrice(vo.getSeckillPrice());
        info.setIntergral(vo.getIntergral());
        Date now = new Date();
        info.setCreateDate(now);
        info.setSeckillDate(now);
        info.setSeckillTime(time);
        info.setSeckillId(seckillId);
        return info;
    }

    public String getNow() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(new Date());
    }

    @Transactional
    public void createRefundLog(OrderInfo orderInfo, Integer type) {
        RefundLog refundLog = new RefundLog();
        String orderNo = orderInfo.getOrderNo();
        refundLog.setOutTradeNo(orderNo);
        if (OrderInfo.PAYTYPE_INTERGRAL.equals(type)) {
            // 如果是积分退款, 金额是积分
            refundLog.setRefundAmount(orderInfo.getIntergral() + "");
        } else {
            // 如果是支付宝退款, 金额是元
            refundLog.setRefundAmount(orderInfo.getSeckillPrice() + "");
        }
        refundLog.setRefundReason("garbage , don't want");
        refundLog.setRefundType(type);
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);
    }
}
